今天真正要講的是overriding。但在進入主題之前,先做點熱身運動:
signature
(註1)不同的方法(函數)並存。'signature'又是另一個術語,指函數的名稱以及其參數的個數和型別,但不包括函數的傳回值(註2)。#include <iostream>
using namespace std;
class Tree {
public:
string breed;
Tree(string myBreed){ // constructor
breed = myBreed;
}
// Overloading: 以下兩個blossom()函數名稱相同,但參數不同,即signature不同。
// C++視作不同的函數。
void blossom(string startDate, string endDate){
cout << "The blooming season of peaches will start from " << startDate << " till " << endDate << " this year." << endl;
}
// signature是函數名稱加上參數(個數、型別),一般不包括傳回值。
void blossom(string month){
cout << this->breed << " blossoms in " << month << '.' << endl;
}
};
int main(void) {
Tree tree("KV Plum");
tree.blossom("March 6", "April 28"); // 呼叫有兩個參數的blossom()。
cout << endl;
tree.blossom("May"); // 呼叫只有一個參數的blossom()。
return 0;
}
blossom()
的member functions。這樣不但不會報錯,在呼叫時,C++的compiler還會依不同參數,自動找到正確的那個函數。Overriding
在繼承的第一篇「起手式」中就有提及,不過未詳加說明。當時是考慮到第一篇是入門磚,不宜放太多材料。所以將繼承的overriding
這個重要概念留到今天才正式介紹。Method overriding, in object-oriented programming, is a language feature that allows a subclass or child class to provide a specific implementation of a method that is already provided by one of its superclasses or parent classes. It allows for a specific type of polymorphism (subtyping).
dine()
的方法,內容為在家自己煮。孝順兒子則認為不好勞煩兩老,他特地也寫了一個dine()
方法,內容則是到外面高檔餐廳享用。最後執行的是兒子的想法。這就是overriding
。不知這比喻恰不恰當。class Tree():
def __init__(self, breed: str, age: int, height: int): # constructor
self.__breed = breed
self.__age = age
self.__height = height
@property
def breed(self) -> str:
return self.__breed
def show_info(self):
print(f'{self.__breed=:10}{self.__age=:<10,}{self.__height=:<10,}')
# Parent class has already defined a blossom() method.
def blossom(self, start_date: str, end_date: str):
print(f'Parent: The blooming season of peaches will start from {start_date} till {end_date} this year.')
class Hardwood(Tree): # Inherited from Tree
... # construtor略
# Child's blossom() will replace(override) the parent's.
def blossom(self, blossom_count: int):
print(f'The estimated blossoms of this {self.breed} would be around {blossom_count:,} this season.')
tree = Hardwood('peach', 1000, 20)
tree.show_info()
print()
tree.blossom(1_500)
tree.show_info()
這行code,由於子類別Hardwood()
並未定義自己的show_info()
方法,所以Python的interpreter就往上找,看父類別有無同名方法。結果找到了,當然就執行囉。tree.blossom(1_500)
這行,Python的interpreter一看:唔,我自己(Hardwood類別)就有blossom()
方法啦(雖然父類別也有個blossom()),不必往上找,就是它了。最後呼叫的是子類別自己的blossom()
,而不是父類別的。blossom()
方法的signature不一樣耶,會不會是這個原因,Python才「要仔唔要乸」(註4),選擇了子類別的方法?class Tree():
def __init__(self, breed: str, age: int, height: int): # constructor
self.__breed = breed
self.__age = age
self.__height = height
@property
def breed(self) -> str:
return self.__breed
def show_info(self):
print(f'{self.__breed=:10}{self.__age=:<10,}{self.__height=:<10,}')
# Parent class has already defined a blossom() method.
def blossom(self, start_date: str, end_date: str):
print(f'Parent: The blooming season of peaches will start from {start_date} till {end_date} this year.')
class Hardwood(Tree): # Inherited from Tree
... # construtor略
# Child's blossom() will replace(override) the parent's.
def blossom(self, start_date: str, end_date: str):
print(f'Child: The blooming season of peaches will start from {start_date} till {end_date} this year.')
blossom()
方法修正成和父類別一樣,都接受兩個str型別的參數。父子兩個blossosm()
's的signature一致了:
tree = Hardwood('peach', 1000, 20)
tree.show_info()
print()
tree.blossom('March 6', 'April 28')vo
OO的終極目的是Polymorphism
這句話嗎?Overriding機制其實就是為日後的多型Polymorphism鋪路。註1: signature的中文有「簽章」、「簽名」、「簽名式」等多個譯名。筆者乾脆都用英文。
註2: 有關signature包不包括函數傳回值問題,一般是不包括,也有人認為包括或在某些情形下包括。而大部分C++的compilers都不允許同一namespace下有兩個名稱相同、參數數目型別相同,只有傳回值不同的函數。
註3: 在C++,如果父子的member functions雖同名但signature不同,呼叫的當然是子類別的function。這時根本不存在overriding問題。
註4: 粵俗,意即寧願留下兒子,趕走母親。